package com.bestcem.xm.user.grpc.client;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.bp.grpc.v1.base.Code;
import com.bestcem.xm.common.core.constant.GrpcClientNames;
import com.bestcem.xm.user.constant.UserCacheKeyConstant;
import com.bestcem.xm.user.constant.UserOutterCacheKeyConstant;
import com.bestcem.xm.user.grpc.client.convert.UserBpWechatGrpcConvert;
import com.bestcem.xm.user.grpc.client.convert.UserWechatGrpcConvert;
import com.bestcem.xm.user.grpc.client.dto.*;
import com.bestcem.xm.user.grpc.client.dto.redis.BaseCacheDTO;
import com.bestcem.xm.user.grpc.client.dto.redis.WxCacheDTO;
import com.bestcem.xm.user.service.dto.user.UserWxDataDTO;
import com.bestcem.xm.wechat.grpc.v1.services.*;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import zhongyan.xm.base.v1.Base;

import javax.annotation.Nullable;
import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;

/**
 * 微信/企业微信相关grpc接口
 *
 * @author Linzhijian <zhijian.lin@idiaoyan.com>
 * @version v1.0
 * @date 2022/5/12 15:50
 */
@Slf4j
@Service(value = "userWechatGrpcService")
public class UserWechatGrpcService {

    @GrpcClient(GrpcClientNames.XM)
    private BpWechatServiceGrpc.BpWechatServiceBlockingStub stub;

    @Resource
    private UserBpWechatGrpcConvert userBpWechatGrpcConvert;

    @Resource
    private UserWechatGrpcConvert userWechatGrpcConvert;

    /**
     * 根据sessionId和redis的key名获取数据
     * cacheKey: f"{wx_mini_session_prefix}:{session_id}"/f"{wx_mini_prefix}:{session_id}"/f"{wxdata_key_prefix}{session_id}"
     *
     * @param sessionId
     * @param prefix
     * @return com.bestcem.xm.user.grpc.client.dto.UserWxDataCacheDTO
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/14 11:21
     */
    public UserWxDataCacheDTO getWxCacheDataBySessionId(String sessionId, String prefix) {
        GetWxCacheDataBySessionIdResponse response = stub.getWxCacheDataBySessionId(GetWxCacheDataBySessionIdRequest.newBuilder().setSessionId(sessionId).setPrefix(prefix).build());
        return userWechatGrpcConvert.response2UserWxDataCacheDTO(response);
    }

    /**
     * 清理缓存的微信消息
     * cacheKey: f"{wxdata_key_prefix}{session_id}"
     *
     * <p>
     * /api/user/v3/wx/fast/org/token/
     * apps_mysql/user/v3/handlers.py:932
     * User:wx_data:{session_id}
     *
     * @param sessionId
     * @return void
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/06 17:23
     */
    public void deleteWxDataBySessionId(String sessionId, String prefix) {
        DeleteWxDataBySessionIdResponse response = stub.deleteWxDataBySessionId(DeleteWxDataBySessionIdRequest.newBuilder().setSessionId(sessionId).setPrefix(prefix).build());
        Integer status = response.getStatus().getCodeValue();
        if (!status.equals(Code.OK.getNumber())) {
            log.error("[USER] grpc deleteWxDataBySessionId error sessionId:{} prefix:{} dto:{}", sessionId, prefix, response.getStatus().getMessage());
        }
    }

    /**
     * 通过code,encryptedData,iv 获取 sessionId，mobile，unionid，openid;
     * /api/authorize/wxminiprogram/users
     * 获取微信加密信息
     *
     * @param code
     * @param encryptedData
     * @param iv
     * @return com.bestcem.xm.user.grpc.client.dto.GetWxAuthViewDTO
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/12 22:41
     */
    public GetWxAuthViewDTO getWxAuthView(String code, String encryptedData, String iv) {
        GetWxAuthViewResponse response = stub.getWxAuthView(GetWxAuthViewRequest.newBuilder().setCode(code).setEncryptedData(encryptedData).setEncryptedIv(iv).build());
        return userWechatGrpcConvert.response2GetWxAuthViewDTO(response);
    }


    /**
     * 当前用户已经绑定了用户
     * 微信消息回复
     *
     * @param openid
     * @param message
     * @return com.bestcem.xm.user.grpc.client.dto.WxMiniSessionDTO
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/23 22:11
     */
    public void sendWxMessage(String openid, String message) {
        SendWxMessageRequest.Builder builder = SendWxMessageRequest.newBuilder();
        builder.setOpenid(openid);
        builder.setMessage(message);
        SendWxMessageResponse response = stub.sendWxMessage(builder.build());

        Integer status = response.getStatus().getCodeValue();
        if (!status.equals(Code.OK.getNumber())) {
            log.error("[USER] grpc sendWxMessage error openid:{} dto:{}", openid, response.getStatus().getMessage());
        }
    }

    /**
     * 获取微信加密信息
     *
     * @param sessionKey    session_key
     * @param encryptedData
     * @param iv
     * @return com.bestcem.xm.user.grpc.client.dto.WxMiniUserMobileDTO
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/02 14:28
     */
    public WxMiniUserMobileDTO getUserPhoneV2(String sessionKey, String encryptedData, String iv) {
        GetUserPhoneV2Request.Builder builder = GetUserPhoneV2Request.newBuilder();
        builder.setSessionKey(sessionKey);
        builder.setEncryptedData(encryptedData);
        builder.setEncryptedIv(iv);
        GetUserPhoneV2Response response = stub.getUserPhoneV2(builder.build());
        return userWechatGrpcConvert.response2WxMiniUserMobileDTO(response);
    }

    /**
     * 缓存微信小程序用户数据 空字符不处理故用Object.nonNull
     * cacheKey: f"{wx_mini_prefix}:{session_id}"
     * wx_mp:{session_id}
     *
     * @param sessionId
     * @param mobileDTO
     * @return void
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/02 14:36
     */
    public void cacheWxMiniUserData(String sessionId, WxMiniUserMobileDTO mobileDTO) {
        Watermark.Builder water = Watermark.newBuilder();
        CacheWxMiniUserDataRequest.Builder builder = CacheWxMiniUserDataRequest.newBuilder();
        if (Objects.nonNull(sessionId)) {
            builder.setSessionId(sessionId);
        }
        if (Objects.nonNull(mobileDTO.getPhone())) {
            builder.setPhone(mobileDTO.getPhone());
        }
        if (Objects.nonNull(mobileDTO.getPurePhone())) {
            builder.setPurePhone(mobileDTO.getPurePhone());
        }
        if (Objects.nonNull(mobileDTO.getCountryCode())) {
            builder.setCountryCode(mobileDTO.getCountryCode());
        }
        if (Objects.nonNull(mobileDTO.getOpenid())) {
            builder.setOpenid(mobileDTO.getOpenid());
        }
        if (Objects.nonNull(mobileDTO.getWatermark())) {
            if (Objects.nonNull(mobileDTO.getWatermark().getAppid())) {
                water.setAppid(mobileDTO.getWatermark().getAppid());
            }
            if (Objects.nonNull(mobileDTO.getWatermark().getTimestamp())) {
                water.setTimestamp(mobileDTO.getWatermark().getTimestamp());
            }
            builder.setWatermark(water.build());
        }
        CacheWxMiniUserDataResponse response = stub.cacheWxMiniUserData(builder.build());
        Integer status = response.getStatus().getCodeValue();
        if (!status.equals(Code.OK.getNumber())) {
            log.error("[USER] grpc cacheWxMiniUserData error sessionId:{} ,dto:{}", sessionId, response.getStatus().getMessage());
        }
    }

    /**
     * 缓存微信公众号用户数据
     * cacheKey: f"{wxdata_key_prefix}{session_id}"
     * User:wx_data:{session_id}
     *
     * @return void
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/02 14:36
     */
    public void cacheUserWxData(String sessionId, UserWxDataDTO wxDataDTO) {

        CacheWxUserInfoRequest.Builder builder = CacheWxUserInfoRequest.newBuilder();
        if (Objects.nonNull(sessionId)) {
            builder.setSessionId(sessionId);
        }
        if (Objects.nonNull(wxDataDTO.getOpenid())) {
            builder.setOpenid(wxDataDTO.getOpenid());
        }
        if (Objects.nonNull(wxDataDTO.getPhone())) {
            builder.setMobile(wxDataDTO.getPhone());
        }
        if (Objects.nonNull(wxDataDTO.getUnionid())) {
            builder.setUnionid(wxDataDTO.getUnionid());
        }
        if (Objects.nonNull(wxDataDTO.getNickname())) {
            builder.setNickname(wxDataDTO.getNickname());
        }
        if (Objects.nonNull(wxDataDTO.getHeadImgUrl())) {
            builder.setHeadImgUrl(wxDataDTO.getHeadImgUrl());
        }
        CacheWxUserInfoResponse response = stub.cacheWxUserInfo(builder.build());
        Integer status = response.getStatus().getCodeValue();
        if (!status.equals(Code.OK.getNumber())) {
            log.error("[USER] grpc cacheUserWxData error sessionId:{} ,dto:{}", sessionId, response.getStatus().getMessage());
        }

    }

    /**
     * 微信小程序通过code获取用户信息
     *
     * @param code code信息
     * @return com.bestcem.xm.user.grpc.client.dto.WxMiniUserInfoDTO
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/06/19 15:25
     */
    public WxMiniUserInfoDTO getWxMiniUserInfo(String code) {
        if (log.isInfoEnabled()) {
            log.info("微信小程序通过code获取用户信息：code:{}", code);
        }

        GetWxMiniUserInfoRequest.Builder builder = GetWxMiniUserInfoRequest.newBuilder();
        builder.setCode(code);
        GetWxMiniUserInfoRequest request = builder.build();
        // 微信小程序通过code获取用户信息
        GetWxMiniUserInfoResponse wxMiniUserInfo = stub.getWxMiniUserInfo(request);
        if (Code.ERROR_VALUE == wxMiniUserInfo.getStatus().getCodeValue()) {
            log.error("微信小程序通过code获取用户信息失败：code:{} dto:{}", code, wxMiniUserInfo.getStatus().getMessage());
            return null;
        }

        return new WxMiniUserInfoDTO(wxMiniUserInfo.getOpenid(), wxMiniUserInfo.getUnionid(), wxMiniUserInfo.getSessionKey());
    }

    /**
     * 缓存微信小程序用户信息
     * cacheKey: f"{wx_mini_session_prefix}:{session_id}"
     *
     * @param info 用户信息
     * @return java.lang.Boolean
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/06/19 15:32
     */
    public Boolean cacheWxMiniUserInfo(CacheWxMiniUserInfoDTO info) {
        if (log.isInfoEnabled()) {
            log.info("缓存微信小程序用户信息：info:{}", JSON.toJSONString(info));
        }

        CacheWxMiniUserInfoRequest cacheWxMiniUserInfoRequest = userBpWechatGrpcConvert.wxMiniUserInfoToRequest(info);
        // 缓存微信小程序用户信息
        CacheWxMiniUserInfoResponse cacheWxMiniUserInfoResponse = stub.cacheWxMiniUserInfo(cacheWxMiniUserInfoRequest);
        if (Code.ERROR_VALUE == cacheWxMiniUserInfoResponse.getStatus().getCodeValue()) {
            log.error("缓存微信小程序用户信息失败：info:{} dto:{}", JSON.toJSONString(info), cacheWxMiniUserInfoResponse.getStatus().getMessage());
            return false;
        }

        return true;
    }


    /**
     * 根据微信openId获取微信用户信息
     *
     * @param openId 微信openId
     * @return unionId, nickname, headimgurl
     * @author XiaoYunSong <ys.xiao@idiaoyan.com>
     * @date 2022/7/13 17:36
     */
    @Nullable
    public UserWxDataCacheDTO getWxUserInfoByOpenId(String openId) {
        if (Objects.isNull(openId)) {
            return null;
        }
        GetWechatUserInfoRequest.Builder builder = GetWechatUserInfoRequest.newBuilder();
        builder.setOpenId(openId);
        try {
            GetWechatUserInfoResponse response =
                    stub.getWechatUserInfo(builder.build());
            if (Objects.isNull(response) || Base.Code.ERROR.equals(response.getStatus().getCode())) {
                log.error("[User] WX getWechatUserInfoByOpenId {} Error; ErrorMsg: {}", openId, response);
                return null;
            }
            if (ObjectUtils.isEmpty(response.getUnionId())) {
                return null;
            }
            UserWxDataCacheDTO result = new UserWxDataCacheDTO();
            result.setUnionid(response.getUnionId());
            result.setNickname(response.getNickname());
            result.setHeadImgUrl(response.getHeadImgUrl());
            return result;
        } catch (Exception e) {
            log.error("[User] WX getWechatUserInfoByOpenId {} Error;", openId, e);
            return null;
        }
    }

    /**
     * 通过前缀+sessionId获取微信缓存信息
     *
     * @param prefix    前缀
     * @param sessionId sessionId
     * @return String
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/15 14:51
     */
    public String getWxCache(String prefix, String sessionId) {
        // 参数校验
        if (StringUtils.isAnyBlank(prefix, sessionId)) {
            return null;
        }
        // 设置参数
        GetWxCacheRequest request = GetWxCacheRequest.newBuilder()
                .setSessionId(sessionId)
                .setPrefix(prefix)
                .build();
        // 设置返回值
        GetWxCacheResponse response = null;
        try {
            response = stub.getWxCache(request);
        } catch (Exception e) {
            log.error("获取微信缓存信息请求失败", e);
        }
        // 返回值处理
        if (response != null && Code.OK_VALUE == response.getStatus().getCodeValue()) {
            return response.getCache();
        } else {
            log.error("获取微信缓存信息请求失败.response:{}", response != null ? response.toString() : null);
        }
        return null;
    }

    /**
     * 通过前缀+sessionId设置微信缓存信息
     *
     * @param prefix    前缀
     * @param sessionId sessionId
     * @param cacheStr  缓存数据
     * @return String
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/15 14:51
     */
    public Boolean updateWxCache(String prefix, String sessionId, String cacheStr) {
        // 参数校验
        if (StringUtils.isAnyBlank(prefix, sessionId, cacheStr)) {
            return Boolean.FALSE;
        }
        // 设置参数
        UpdateWxCacheRequest request = UpdateWxCacheRequest.newBuilder()
                .setSessionId(sessionId)
                .setPrefix(prefix)
                .setCache(cacheStr)
                .build();
        // 设置返回值
        UpdateWxCacheResponse response = null;
        try {
            response = stub.updateWxCache(request);
        } catch (Exception e) {
            log.error("设置微信缓存信息请求失败", e);
        }
        // 返回值处理
        if (response != null && Code.OK_VALUE == response.getStatus().getCodeValue()) {
            return Boolean.TRUE;
        } else {
            log.error("设置微信缓存信息请求失败.response:{}", response != null ? response.toString() : null);
        }
        return Boolean.FALSE;
    }

    /**
     * 将缓存字符串转换成缓存对象
     *
     * @param prefix
     * @param sessionId
     * @param clazz
     * @return T
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/15 15:36
     */
    private <T extends BaseCacheDTO> T getWxCacheByBusiness(String prefix, String sessionId, Class<T> clazz) {
        // 校验参数
        if (StringUtils.isBlank(sessionId)) {
            return null;
        }
        // 通过前缀+sessionId获取微信缓存信息
        String cacheStr = this.getWxCache(prefix, sessionId);
        if (StringUtils.isBlank(cacheStr)) {
            return null;
        }
        // 设置返回值
        T cacheDTO = JSON.parseObject(cacheStr, clazz);
        cacheDTO.setOriginalCacheStr(cacheStr);
        return cacheDTO;
    }

    /**
     * 将缓存对象转换成缓存字符串
     *
     * @param cacheDTO
     * @return String
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/15 15:34
     */
    private String wxCacheObjToStr(BaseCacheDTO cacheDTO) {
        String cacheObjStr = JSON.toJSONString(cacheDTO);
        if (StringUtils.isNotBlank(cacheDTO.getOriginalCacheStr())) {
            JSONObject originalCacheObj = JSON.parseObject(cacheDTO.getOriginalCacheStr());
            JSONObject cacheObj = JSON.parseObject(cacheObjStr);
            for (Map.Entry<String, Object> entry : cacheObj.entrySet()) {
                originalCacheObj.put(entry.getKey(), entry.getValue());
            }
            cacheObjStr = JSON.toJSONString(originalCacheObj);
        }
        return cacheObjStr;
    }

    /**
     * 获取微信缓存用户信息
     *
     * @param sessionId
     * @return WxCacheDTO
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/15 14:54
     */
    public WxCacheDTO getWxSessionInfo(String sessionId) {
        return this.getWxCacheByBusiness(UserOutterCacheKeyConstant.WX_MINI_SESSION_PREFIX, sessionId, WxCacheDTO.class);
    }

    /**
     * 设置微信缓存用户信息
     *
     * @param sessionId
     * @param wxCacheDTO
     * @return Boolean
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/15 15:28
     */
    public Boolean cacheWxSessionInfo(String sessionId, WxCacheDTO wxCacheDTO) {
        return this.updateWxCache(UserOutterCacheKeyConstant.WX_MINI_SESSION_PREFIX, sessionId,
                this.wxCacheObjToStr(wxCacheDTO));
    }

    /**
     * 获取企业微信缓存用户信息
     *
     * @param sessionId
     * @return WxCacheDTO
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/15 14:54
     */
    public WxCacheDTO getWxworkSessionInfo(String sessionId) {
        return this.getWxCacheByBusiness(UserCacheKeyConstant.WXWORK_MINI_SESSION_PREFIX, sessionId, WxCacheDTO.class);
    }

    /**
     * 设置企业微信缓存用户信息
     *
     * @param sessionId
     * @param wxCacheDTO
     * @return Boolean
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/7/15 15:28
     */
    public Boolean cacheWxworkSessionInfo(String sessionId, WxCacheDTO wxCacheDTO) {
        return this.updateWxCache(UserCacheKeyConstant.WXWORK_MINI_SESSION_PREFIX, sessionId,
                this.wxCacheObjToStr(wxCacheDTO));
    }
}
